package com.yuju.common.util.http;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.Args;
import org.apache.http.util.ByteArrayBuffer;
import org.apache.http.util.EntityUtils;

import com.yuju.util.Utils;

/**
 *类名：HttpClientHandler
 *功能：HttpClient方式访问
 *详细：获取远程HTTP数据
 *版本：1.0
 *日期：2015-08-11
 */
public class HttpClientHandler {
	private static HttpClientHandler httpClientHandler = new HttpClientHandler();

	/**
	 * 工厂方法
	 * 
	 * @return
	 */
	public static HttpClientHandler getInstance() {
		return httpClientHandler;
	}

	/**
	 * 私有的构造方法
	 */
	private HttpClientHandler() {
	}

	/**
	 * 执行Http请求
	 * @author xue
	 * @date 2016-01-07
	 * @param httpWrapper 请求数据
	 * @param 回调函数
	 * @throws IOException
	 */
	public void execute(HttpWrapper httpWrapper, IHttpClientCallBack iccb) throws IOException {
		BasicClientCookie basicClientCookie = new BasicClientCookie(httpWrapper.getTokenName(), httpWrapper.getTokenVal());
		basicClientCookie.setDomain(httpWrapper.getServerHost());
		
		basicClientCookie.setPath("/");
		basicClientCookie.setSecure(false);

		BasicCookieStore cookieStore = new BasicCookieStore();
		cookieStore.addCookie(basicClientCookie);

		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultCookieStore(cookieStore).build();


		CloseableHttpResponse response1 = null;
		
		if (httpWrapper.getMethod().equalsIgnoreCase(HttpWrapper.METHOD_GET)) {
			HttpGet httpget = new HttpGet(httpWrapper.getUrl() + (StringUtils.isNotEmpty(httpWrapper.getQueryString()) ? "?" + httpWrapper.getQueryString() : ""));
			for (Map.Entry<String, Object> entry : httpWrapper.getHeaders().entrySet()) {
				httpget.setHeader(entry.getKey(), entry.getValue().toString());
	        }
			response1 = httpclient.execute(httpget);
		} else if (httpWrapper.getMethod().equalsIgnoreCase(HttpWrapper.METHOD_POST)) {
			HttpPost httppost = new HttpPost(httpWrapper.getUrl());
			for (Map.Entry<String, Object> entry : httpWrapper.getHeaders().entrySet()) {
				httppost.setHeader(entry.getKey(), entry.getValue().toString());
	        }
			Map<String, Object> headers = httpWrapper.getHeaders();
			if ("application/json".equals(headers.get("Content-Type"))) {
				StringEntity entity = new StringEntity(httpWrapper.getParam(),"utf-8");
				entity.setContentEncoding("UTF-8");    
				entity.setContentType("application/json");    
				httppost.setEntity(entity);
			} else {
				httppost.setEntity(new UrlEncodedFormEntity(httpWrapper.getParameters()));
			}
			response1 = httpclient.execute(httppost);
		}

		try {
			HttpEntity entity = response1.getEntity();
			
			String responseContext = getContent(entity); // EntityUtils.toString(entity, "UTF-8"); 

			cookieHandler(cookieStore, httpWrapper);
			
			if (null != iccb)
				httpWrapper.handleResponse(iccb, responseContext);
			else 
				httpWrapper.handleResponse(responseContext);
		} catch (RuntimeException e) {
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (response1 != null) {
				response1.close();
			}
			if (httpclient != null) {
				httpclient.close();
			}
		}
	}
	
	/**
	 * 处理cookies
	 * @author xue
	 * @date 2016-01-07
	 * @param cookieStore
	 */
	public void cookieHandler(BasicCookieStore cookieStore, HttpWrapper httpWrapper) {
		System.out.println("Initial set of cookies:");
		List<Cookie> cookies = cookieStore.getCookies();
		if (cookies.isEmpty()) {
			System.out.println("None");
		} else {
			for (Cookie cookie : cookies) {
				if (cookie != null) {
					System.out.println(cookie.toString());
					if (cookie != null && httpWrapper.getTokenName().equals(cookie.getName())) {
						if (Utils.isNotNull(cookie.getValue())) {
							HttpClientCookieManager.storeToken(httpWrapper.getTokenName(), cookie.getValue());
						}
					}
				}
			}
		}
	}
	
	/**
	 * 取得响应的内容
	 * @author xue
	 * @date 2016-01-07
	 * @param entity 响应实体
	 * @return
	 * @throws UnsupportedOperationException
	 * @throws IOException
	 */
	public String getContent(HttpEntity entity) throws UnsupportedOperationException, IOException {
		String responseContext = null;
		final InputStream instream = entity.getContent();
		try {
			if (instream == null) {
				return null;
			}
			
			/*Args.check(entity.getContentLength() <= Integer.MAX_VALUE, "HTTP entity too large to be buffered in memory");
			int i = (int) entity.getContentLength();
			if (i < 0) {
				i = 4096;
			}
			final ByteArrayBuffer buffer = new ByteArrayBuffer(i);
			final byte[] tmp = new byte[4096];
			int l;
			while ((l = instream.read(tmp)) != -1) {
				buffer.append(tmp, 0, l);
			}
			responseContext = new String(buffer.toByteArray(), entity.getContentType().getValue().split(";")[1].split("=")[1]);*/
			
			Args.check(entity.getContentLength() <= Integer.MAX_VALUE,
					"HTTP entity too large to be buffered in memory");
			int i = (int) entity.getContentLength();
			if (i < 0) {
				i = 4096;
			}
			final ByteArrayBuffer buffer = new ByteArrayBuffer(i);
			final byte[] tmp = new byte[4096];
			int l;
			while ((l = instream.read(tmp)) != -1) {
				buffer.append(tmp, 0, l);
			}
			responseContext = new String(buffer.toByteArray(),entity.getContentType().getValue().split(";")[1].split("=")[1]);
		} finally {
			if(instream != null)
				instream.close();
		}
		
		return responseContext;
	}

	/**
	 * 将NameValuePairs数组转变为字符串
	 * 
	 * @author xue
	 * @date 2016-01-07
	 * @param nameValues
	 * @return
	 */
	protected String toString(NameValuePair[] nameValues) {
		if (nameValues == null || nameValues.length == 0) {
			return "null";
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < nameValues.length; i++) {
			NameValuePair nameValue = nameValues[i];

			if (i == 0) {
				buffer.append(nameValue.getName() + "=" + nameValue.getValue());
			} else {
				buffer.append("&" + nameValue.getName() + "="
						+ nameValue.getValue());
			}
		}

		return buffer.toString();
	}
}
